export function patch(oldVnode, vnode) {
  // console.log('[ oldVnode, vnode ] >', oldVnode, vnode)
  // console.log('oldVnode, vnode',oldVnode, vnode);
  // vue 渲染流程9
  // 转变成真实dom
  // 更新后 新增diff算法
  // 第一次直接替换
  // console.log('[ oldVnode ] >', oldVnode,vnode)
  // 当组件没有这个元素直接去创建
  if(!oldVnode){
    
    return createEl(vnode)
  }
  if (oldVnode.nodeType === 1) {
    let el = createEl(vnode)
    // 进行替换 放到页面上
    // vue 渲染流程10
    let parentEl = oldVnode.parentNode
    parentEl.insertBefore(el, oldVnode.nextsibling)
    parentEl.removeChild(oldVnode)
    return el
  }else{
    // 第二次通过算法进行替换
    // console.log("第二次");
    // 1.如果标签不一样直接替换
    if(oldVnode.tag !== vnode.tag){
      return oldVnode.el.parentNode.replaceChild(createEl(vnode),oldVnode.el)
    }
    // 2.标签一样 文本不一样
    if(!oldVnode.tag){
      if(oldVnode.text !== vnode.text){
        return oldVnode.el.textContent = vnode.text
      }
    }
    let el = vnode.el = oldVnode.el
    // 属性处理(标签一样) 1 直接复制 
    updataRpors(vnode,oldVnode.date)

    // 多种情况 
    const oldChildren = oldVnode.children || []
    const newChildren = vnode.children || []
    // console.log('[ oldChildren ] >', oldChildren)
    // console.log('[ newChildren ] >', newChildren)
    if(oldChildren.length >0 && newChildren.length>0){ // 3.老的有儿子 新的也有儿子
      // 使用双指针来进行比对
      updataChild(oldChildren,newChildren,el)
    }else if(oldChildren.length >0){ // 2.老的元素有儿子 新的没有
      el.innerHTML = ''

    }else if(newChildren.length >0){ // 1.老的没有儿子 新的有儿子
      for (let i = 0; i < newChildren.length; i++) {
        const child = newChildren[i];
        // 拿到虚拟dom进行实例进行渲染
        el.appendChild(createEl(child))
      }
    }
  }
}

// updataRpors
function updataChild(oldChildren,newChildren,parent){
    // console.log('[ oldChildren,newChildren,el ] >',oldChildren,newChildren,el)

    // diff做了很多优化
    // 操作dom  常用的逻辑 头部添加 尾部添加 倒叙和正序的方式
    // 双指针的方法  // 学习双指针
    // 涉及到了一个面试题就是关于key为什么不能用索引 因为他会给你进行交叉判断 以为你是一样的就不会更换里面的内容
    let oldStartIndex = 0 // 老的开头索引
    let oldStartVnode = oldChildren[oldStartIndex] // 老的开始元素 
    let oldEndIndex = oldChildren.length - 1 // 老的结束索引
    let oldEndVnode = oldChildren[oldEndIndex] // 老的结束元素


    let newStartIndex = 0 // 新的开头索引
    let newStartVnode = newChildren[newStartIndex] // 新的开始元素 
    let newEndIndex = newChildren.length - 1 // 新的结束索引
    let newEndVnode = newChildren[newEndIndex] // 新的结束元素 

    let map = makeIndexBykey(oldChildren)
    // 判断当前的索引不能超出
    while(oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex){
      if(isSomeVnode(oldStartVnode,newStartVnode)){ // 从头开始对比
        // 假如里面有子项继续走
        patch(oldStartVnode,newStartVnode)
        oldStartVnode = oldChildren[++oldStartIndex]
        newStartVnode = newChildren[++newStartIndex]
      }else if(isSomeVnode(oldEndVnode,newEndVnode)){  // 从结尾对比
        // 假如里面有子项继续走
        patch(oldEndVnode,newEndVnode)
        oldEndVnode = oldChildren[--oldEndIndex]
        newEndVnode = newChildren[--newEndIndex]
      }else if(isSomeVnode(oldStartVnode,newEndVnode)){ // 头和尾对比
        // 假如里面有子项继续走
        patch(oldStartVnode,newEndVnode)
        oldStartVnode = oldChildren[++oldStartIndex]
        newEndVnode = newChildren[--newEndIndex]
      }else if(isSomeVnode(oldEndVnode,newStartVnode)){ // 头和尾对比
        // 假如里面有子项继续走
        patch(oldEndVnode,newStartVnode)
        oldEndVnode = oldChildren[--oldEndIndex]
        newStartVnode = newChildren[++newStartIndex]
      }else{
        let moveIndex = map[newStartVnode.key]
        // 没找到
        if(moveIndex == undefined){
          parent.insertBefore(createEl(newStartVnode),oldStartVnode.el)
        }else{ // 找到了
          // 获取到移动的元素
          let moveVnode = oldChildren[moveIndex]
          oldChildren[moveIndex] = null
          parent.insertBefore(moveVnode.el,oldStartVnode.el)
          
          patch(moveVnode,newStartVnode)
        }
        // 插入的元素可能还有儿子
        newStartVnode = newChildren[++newStartIndex]

      }
    }

    // 假如有多余的 进行添加
    if(newStartIndex<=newEndIndex){
      for(let i = newStartIndex;i<=newEndIndex;i++){
        parent.appendChild(createEl(newChildren[i]))
      }
    }

    // 将老的多余的去掉
    if(oldStartIndex<=oldEndIndex){
      for(let i = oldStartIndex;i<=oldEndIndex;i++){
        let child = oldChildren[i]
        if(child != null){
          parent.removeChild(child.el)
        }
        
      }
    }

}
// 创建旧元素的映射表
function makeIndexBykey(child){
  let map = {}
  child.forEach((item,index)=>{
    if(item.key){
      map[item.key] = index
    }
  })
  return map
}


function isSomeVnode(oldContext,newContext){
  return (oldContext.tag == newContext.tag) && (oldContext.key == newContext.key)
}
// 添加属性
function updataRpors(vnode,oldProps={}){
  let newProps = vnode.date || {} //获取当前新节点的属性
  let el = vnode.el // 获取当前真实节点
  for(let key in newProps){
    if(key == "style"){
      for(let styleName in newProps.style){
        el.style[styleName] = newProps.style[styleName]
      }
    } else if(key === 'class'){
      el.className = newProps.class
    } else{
      el.setAttribute(key,newProps[key])
    }
  }
}
// 变成真实的dom
export function createEl(vnode) {
  let {vm, tag, date, key, children, text } = vnode;
  if (typeof tag === 'string') { //创建元素
  //获取到的可能是组件标签
  
    if(createcomponent(vnode)){
      return vnode.componetInstance.$el
    }else{ // 标签
      vnode.el = document.createElement(tag)
      updataRpors(vnode)
      // if (children.length > 0) {
        children && children.forEach(child => {
          // 添加进去分类型
          vnode.el.appendChild(createEl(child))
        });
      // }
    }
    

  } else {  // 文本
    vnode.el = document.createTextNode(text)
  }
  return vnode.el
}
function createcomponent(vnode){
  // console.log('[ vnode(vnode) ] >',vnode )
  let i = vnode.date
  if((i=i.hook)&&(i=i.init)){
    // console.log('[ i ] >', i)
    i(vnode)//初始化 创建一个子组件实例
  }
  if(vnode.componetInstance){
    return true
  }
  return false

}